/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_ssap_server_service.h"
#include "sle_ssap_server_hal.h"
#include "sle_hilog.h"
#include "sle_connect_hal.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {

class SleSsapServerService::SleSsapServerServiceCallback {
public:
    SleSsapServerServiceCallback() = default;
    ~SleSsapServerServiceCallback() = default;

    static void OnStartService(uint8_t serverId, uint16_t serviceHandle, SleHalErrorCode errCode);
    static void OnAllServiceDelete(uint8_t serverId, SleHalErrorCode errCode);
    static void OnReadRequest(uint8_t serverId, uint16_t connectId, const SsapsReqReadCbParam *reqReadCbPara,
                SleHalErrorCode errCode);
    static void OnWriteRequest(uint8_t serverId, uint16_t connectId, const SsapsReqWriteCbPara *reqWriteCbPara,
                SleHalErrorCode errCode);
    static void OnMtuInfoChanged(
        uint8_t serverId, uint16_t connectId ,const SsapMtuInfo *mtuInfo, SleHalErrorCode errCode);
    static SleSsapsHalCallbacks *BuildHalSsapServerCallback();

private:
    static SleSsapsHalCallbacks halCallback_;
};

void SleSsapServerService::SleSsapServerServiceCallback::OnStartService(
    uint8_t serverId, uint16_t serviceHandle, SleHalErrorCode errCode)
{
    SLE_LOGD("OnStartService In");
    auto serverService = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService->callback_, "ssap server service callback null error!");
    serverService->callback_->OnStartService(serverId, serviceHandle, (SleErrorCode)errCode);
}

void SleSsapServerService::SleSsapServerServiceCallback::OnAllServiceDelete(uint8_t serverId, SleHalErrorCode errCode)
{
    SLE_LOGD("OnAllServiceDelete In");
    auto serverService = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService->callback_, "ssap server service callback null error!");
    serverService->callback_->OnAllServiceDelete(serverId, (SleErrorCode)errCode);
}

void SleSsapServerService::SleSsapServerServiceCallback::OnReadRequest(uint8_t serverId, uint16_t connectId,
    const SsapsReqReadCbParam *reqReadCbPara, SleHalErrorCode errCode)
{
    SLE_LOGD("OnReadRequest In");
    auto serverService = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService->callback_, "ssap server service callback null error!");
    SLE_ASSERT_AND_RETURN_LOG(reqReadCbPara, "reqReadCbPara null error!");
    serverService->callback_->OnReadRequest(serverId, connectId, *reqReadCbPara, (SleErrorCode)errCode);
}

void SleSsapServerService::SleSsapServerServiceCallback::OnWriteRequest(uint8_t serverId, uint16_t connectId,
    const SsapsReqWriteCbPara *reqWriteCbPara, SleHalErrorCode errCode)
{
#if 0
    SLE_LOGD("OnWriteRequest In");
#endif
    auto serverService = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService->callback_, "ssap server service callback null error!");
    SLE_ASSERT_AND_RETURN_LOG(reqWriteCbPara, "write request callback param null error!");
    serverService->callback_->OnWriteRequest(serverId, connectId, *reqWriteCbPara, (SleErrorCode)errCode);
}

void SleSsapServerService::SleSsapServerServiceCallback::OnMtuInfoChanged(uint8_t serverId, uint16_t connectId,
    const SsapMtuInfo *mtuInfo, SleHalErrorCode errCode)
{
    SLE_LOGD("OnMtuInfoChanged In");
    auto serverService = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService->callback_, "ssap server service callback null error!");
    SLE_ASSERT_AND_RETURN_LOG(mtuInfo, "mtu info null error!");
    serverService->callback_->OnMtuInfoChanged(serverId, connectId, *mtuInfo, (SleErrorCode)errCode);
    SLE_ASSERT_AND_RETURN_LOG(errCode == SLE_HAL_SUCCESS, "ssap server service set mtu info status error!");
    uint16_t data_len = mtuInfo->mtuSize + DATA_LEN_BIGGER;
    SleHalErrorCode ret = SleConnectHalSetDataLength(connectId, data_len);
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "set data buffer length failed!");
}

SleSsapsHalCallbacks SleSsapServerService::SleSsapServerServiceCallback::halCallback_;
SleSsapsHalCallbacks* SleSsapServerService::SleSsapServerServiceCallback::BuildHalSsapServerCallback()
{
    SLE_LOGD("SleSsapServerService In");
    halCallback_.OnSsapsServiceStartedCb = OnStartService;
    halCallback_.OnSsapsAllServiceRemovedCb = OnAllServiceDelete;
    halCallback_.OnSsapsRecvReadReqCb = OnReadRequest;
    halCallback_.OnSsapsRecvWriteReqCb = OnWriteRequest;
    halCallback_.OnSsapsMtuChangeCb = OnMtuInfoChanged;
    return &halCallback_;
}

SleSsapServerService::SleSsapServerService()
{
    SLE_LOGD("SleSsapServerService In");
    SleHalErrorCode ret = InitSleSsapsHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "init sle ssap server hal failed!");
    serviceCallback_ = std::make_unique<SleSsapServerServiceCallback>();
    SLE_ASSERT_AND_RETURN_LOG(serviceCallback_, "create service callback ptr failed!");
    ret = SleSsapsHalRegisterCallbacks(serviceCallback_->BuildHalSsapServerCallback());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "register hal ssap server callback failed!");
}

SleSsapServerService::~SleSsapServerService()
{
    SLE_LOGD("~SleSsapServerService In");
    SleHalErrorCode ret = DeinitSleSsapsHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "Deinit sle ssaps hal failed!");
    serviceCallback_ = nullptr;
}

SleSsapServerService* SleSsapServerService::GetInstance()
{
    static SleSsapServerService instance;
    return &instance;
}

SleErrorCode SleSsapServerService::RegisterSsapServer(const Uuid &uuid, uint8_t &serverId)
{
    SLE_LOGD("RegisterSsapServer In");
    SleUuid appUuid = uuid.ConvertToSleUuid();
    SleHalErrorCode ret = SleSsapsHalAddServer(&appUuid, &serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "register ssap server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::UnregisterSsapServer(uint8_t serverId)
{
    SLE_LOGD("UnregisterSsapServer In");
    SleHalErrorCode ret = SleSsapsHalRemoveServer(serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "unregister ssap server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::AddService(uint8_t serverId, const Uuid &uuid, bool isPrimary, uint16_t &handle)
{
    SLE_LOGD("AddService In");
    SleUuid serviceUuid = uuid.ConvertToSleUuid();
    SleHalErrorCode ret = SleSsapsHalAddService(serverId, &serviceUuid, isPrimary, &handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "add service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::AddProperty(
    uint8_t serverId, uint16_t serviceHandle, const SsapServerPropertyParam &param, uint16_t &handle)
{
    SLE_LOGD("AddProperty In");
    SsapsPropertyParam property;
    param.ConvertToSsapsPropertyParam(property);
    SleHalErrorCode ret = SleSsapsHalAddProperty(serverId, serviceHandle, &property, &handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "add property failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::AddDescriptor(
    uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle, const SsapServerDescriptorParam &param)
{
    SLE_LOGD("AddDescriptor In");
    SsapsDescriptorParam descriptor;
    param.ConvertToSsapsDescriptorParam(descriptor);
    uint16_t descriptorHandle;
    SleHalErrorCode ret = SleSsapsHalAddDescriptor(serverId, serviceHandle, propHandle, &descriptor, &descriptorHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "add descriptor failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::RemoveAllServices(uint8_t serverId)
{
    SLE_LOGD("RemoveAllServices In");
    SleHalErrorCode ret = SleSsapsHalRemoveAllServices(serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "remove all services failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::StartService(uint8_t serverId, uint16_t serviceHandle)
{
    SLE_LOGD("StartService In");
    SleHalErrorCode ret = SleSsapsHalStartService(serverId, serviceHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "start service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::SendResponse(
    uint8_t serverId, uint16_t connectId, const SsapServerSendRspParam &param)
{
    SLE_LOGD("SendResponse In");
    SsapsSendRspParam rspParam;
    param.ConvertToSsapsSendRspParam(rspParam);
    SleHalErrorCode ret = SleSsapsHalSendResponse(serverId, connectId, &rspParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "send response failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::NotifyIndicate(
    uint8_t serverId, uint16_t connectId, const SsapServerNotifyParam &param)
{
#if 0
    SLE_LOGD("NotifyIndicate In");
#endif
    SsapsNotifyParam notifyParam;
    param.ConvertToSsapsNotifyParam(notifyParam);
    SleHalErrorCode ret = SleSsapsHalNotifyIndicate(serverId, connectId, &notifyParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "notify indicate failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::NotifyIndicateByUuid(
    uint8_t serverId, uint16_t connectId, const SsapServerNotyfyByUuidParam &param)
{
    SLE_LOGD("NotifyIndicateByUuid In");
    SsapsNotyfyByUuidParam notifyParam;
    param.ConvertToSsapsNotyfyByUuidParam(notifyParam);
    SleHalErrorCode ret = SleSsapsHalNotifyIndicateByUuid(serverId, connectId, &notifyParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "notify indicate by uuid failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::SetServerMtuInfo(uint8_t serverId, uint32_t mtu, uint16_t version)
{
    SLE_LOGD("SetServerMtuInfo In");
    SsapMtuInfo mtuInfo = {
        .mtuSize = mtu,
        .version = version,
    };
    SleHalErrorCode ret = SleSsapsHalSetMtuInfo(serverId, &mtuInfo);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "set server mtu info failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::RegisterSsapServerCallback(ISsapServerCallback &callback)
{
    SLE_LOGD("RegisterSsapServerCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ != &callback, SLE_ERR_INVALID_PARAM, "callback already registered error!");
    callback_ = &callback;
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerService::UnregisterSsapServerCallback(ISsapServerCallback &callback)
{
    SLE_LOGD("UnregisterSsapClientCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ == &callback, SLE_ERR_INVALID_PARAM, "callback already unregistered error!");
    callback_ = nullptr;
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS